﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace ECANPort
{
    /// <summary>
    /// Can数据组织结构体
    /// </summary>
    public struct CanCom_HTB
    {
        public uint CanIndex;
        public CAN_OBJ[] gRecMsgBuf;
        public uint gRecMsgBufHead;
        public uint gRecMsgBufTail;

        public CAN_OBJ[] gSendMsgBuf;
        public uint gSendMsgBufHead;
        public uint gSendMsgBufTail;
    }

    public enum E_CanSendModel
    {
        TimeModel,
        FastModel
    }

    /// <summary>
    /// Can收发逻辑
    /// </summary>
    public class CanComProc
    {
        // Fields
        public bool EnableProc;
        public const int REC_MSG_BUF_MAX = 10000;
        public const int SEND_MSG_BUF_MAX = 10000;
        public static int REC_MSG_Hz_ms = 20;
        public static int SEND_MSG_Hz_ms = 20;

        public CanCom_HTB[] HTBs;
        /// <summary>
        /// 几路Can通道
        /// </summary>
        public int CanCount { get; private set; }
        private Timer _RecTimer;
        private Timer _SendTimer;

        private AutoResetEvent RecEvent;
        private TimerCallback RecTimerDelegate;
        private AutoResetEvent SendEvent;
        private TimerCallback SendTimerDelegate;


        public (bool ok, CanCom_HTB HTB, int RefIndex) Get_HTBByValue(uint CanIndex)
        {
            for (int i = 0; i < HTBs.Length; i++)
            {
                if (HTBs[i].CanIndex == CanIndex)
                {
                    return (true, HTBs[i], i);
                }
            }
            return (false, new CanCom_HTB(), 0);
        }

        public CanComProc(uint[] mCanIndex)
        {
            this.CanCount = mCanIndex.Length;
            HTBs = new CanCom_HTB[CanCount];

            for (int i = 0; i < CanCount; i++)
            {
                HTBs[i].CanIndex = mCanIndex[i];
                HTBs[i].gSendMsgBuf = new CAN_OBJ[SEND_MSG_BUF_MAX];
                HTBs[i].gSendMsgBufHead = 0;
                HTBs[i].gSendMsgBufTail = 0;

                HTBs[i].gRecMsgBuf = new CAN_OBJ[REC_MSG_BUF_MAX];
                HTBs[i].gRecMsgBufHead = 0;
                HTBs[i].gRecMsgBufTail = 0;
            }

            this.EnableProc = false;
            this.RecEvent = new AutoResetEvent(false);
            this.RecTimerDelegate = new TimerCallback(this.RecTimer_Tick);
            this._RecTimer = new Timer(this.RecTimerDelegate, this.RecEvent, 0, REC_MSG_Hz_ms);
            this.SendEvent = new AutoResetEvent(false);
            this.SendTimerDelegate = new TimerCallback(this.SendTimer_Tick);
            this._SendTimer = new Timer(this.SendTimerDelegate, this.SendEvent, 0, SEND_MSG_Hz_ms);
        }

        private void ReadMessages(ref CanCom_HTB HTB)
        {
            CAN_OBJ mMsg = new CAN_OBJ();
            int sCount = 0;
            do
            {
                uint mLen = 1;
                var st = ECANDLL.Receive(1, 0, HTB.CanIndex, out mMsg, mLen, 1);

                if (!((st == ECANStatus.STATUS_OK) & (mLen > 0)))
                {
                    break;
                }

                HTB.gRecMsgBuf[HTB.gRecMsgBufHead].ID = mMsg.ID;
                HTB.gRecMsgBuf[HTB.gRecMsgBufHead].DataLen = mMsg.DataLen;
                HTB.gRecMsgBuf[HTB.gRecMsgBufHead].data = mMsg.data;
                HTB.gRecMsgBuf[HTB.gRecMsgBufHead].ExternFlag = mMsg.ExternFlag;
                HTB.gRecMsgBuf[HTB.gRecMsgBufHead].RemoteFlag = mMsg.RemoteFlag;
                HTB.gRecMsgBufHead += 1;
                if (HTB.gRecMsgBufHead >= REC_MSG_BUF_MAX)
                {
                    HTB.gRecMsgBufHead = 0;
                }
                sCount++;
            }
            while (sCount < 500);
        }
        public event Action CanSendErr;
        public event Action CanSendOK;
        public static E_CanSendModel CanSendModel;
        public static int CanComSendCount =200;
        private void SendMessages(ref CanCom_HTB HTB)
        {
            int sCount = 0;
            do
            {
                if (HTB.gSendMsgBufHead == HTB.gSendMsgBufTail)
                {
                    break;
                }
                CAN_OBJ mMsg = HTB.gSendMsgBuf[HTB.gSendMsgBufTail];
                HTB.gSendMsgBufTail += 1;
                if (HTB.gSendMsgBufTail >= SEND_MSG_BUF_MAX)
                {
                    HTB.gSendMsgBufTail = 0;
                }
                uint mLen = 1;
                if (ECANDLL.Transmit(1, 0, HTB.CanIndex, ref mMsg, (ushort)mLen) != ECANStatus.STATUS_OK)
                {
                    Console.WriteLine("Transmit -> STATUS_ERR!");
                    CanSendErr?.Invoke();
                    break;//发送错误时直接退出:30W次错误=>1千多线程
                }
                else
                {
                    CanSendOK?.Invoke();
                    if (CanSendModel == E_CanSendModel.TimeModel)
                    {
                        //TODO:确认那种读法更好
                        break;
                    }
                }
                sCount++;
            }
            while (sCount < CanComSendCount);
        }

        public void RecTime()
        {
            if (this.EnableProc)
            {
                for (int i = 0; i < CanCount; i++)
                {
                    this.ReadMessages(ref HTBs[i]);
                }

            }
        }

        private void RecTimer_Tick(object mObject)
        {
            this.RecTime();
        }

        private void SendTimer_Tick(object mObject)
        {
            this.SendTime();
        }

        public void SendTime()
        {
            if (this.EnableProc)
            {
                for (int i = 0; i < CanCount; i++)
                {
                    this.SendMessages(ref HTBs[i]);
                }
            }
        }

        public void Close()
        {
        }


    }

}
